<?php

namespace app\service;

use app\core\Constant;
use app\core\exception\BusinessException;
use app\core\Request;
use app\core\Service;
use app\core\util\Random;
use app\core\util\Tree;
use app\model\SysPermission;
use app\model\SysRoleMenu;
use app\model\SysRolePerm;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\facade\Cache;
use think\facade\Db;

/**
 * @extends Service<PermissionService>
 */
class PermissionService extends Service
{
    public function getSysPermissionList($appKey, $searchQuery = null)
    {
        $menus = SysPermission::where('app_key', $appKey)
            ->where(function ($q) use ($searchQuery) {
                if (!empty($searchQuery)) {
                    if (!empty($searchQuery['name'])) {
                        $q = $q->where('name', 'like', "%" . $searchQuery['name'] . "%");
                    }
                    if (!empty($searchQuery['status'])) {
                        $q->where('status', $searchQuery['status']);
                    }
                }
            });
        $pid = $menus->order('parent_id asc')->value('parent_id');
        $list = $menus->order("order_num desc")->select()->toArray();
        if (count($list) > 0 && empty($searchQuery['name'])) {
            $list = Tree::invoke()->buildTree($list, $pid, 'permission_id');
        }
        return $list;
    }

    public function getPermissionInfo($id): array
    {
        $menu = SysPermission::find($id);
        if (!$menu) {
            throw new BusinessException('权限不存在');
        }
        return $menu->toArray();
    }

    public function save($data, $id = null)
    {
        $saveData = [
            'parent_id' => $data['parent_id'] ?? 0,
            'app_key' => $data['app_key'],
            'name' => $data['name'],
            'order_num' => $data['order_num'] ?? 0,
            'status' => $data['status'] ?? Constant::STATUS_NORMAL,
            'perms' => $data['perms'],
            'remark' => $data['remark'] ?? null,
        ];

        if (!empty($id)) {
            if ($saveData['parent_id'] == $id) {
                throw new BusinessException("上级目录不能选择自己");
            }
            $menu = SysPermission::where('permission_id', $id)->find();
            if (!$menu) {
                throw new BusinessException("权限不存在");
            }
            if ($saveData['perms'] != $menu['perms']) {
                $this->checkPermsUnique($saveData['perms']);
            }
            $menu->save($saveData);
        } else {
            if (!empty($saveData['perms'])) {
                $this->checkPermsUnique($saveData['perms']);
            }
            SysPermission::create($saveData);
        }

        return true;
    }

    /**
     * @param $perms
     * @return bool
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function checkPermsUnique($perms): bool
    {
        if (SysPermission::where('perms', $perms)->find()) {
            throw new BusinessException('权限标识已存在');
        }
        return true;
    }

    public function getPermissionTree($appKey)
    {
        $menus = SysPermission::where('status', Constant::STATUS_NORMAL)
            ->where('app_key', $appKey)
            ->field("permission_id as `key`, name as `title`, parent_id")
            ->select()->toArray();
        return Tree::invoke()->buildTree($menus, 0, 'key');
    }

    public function delById($id)
    {
        $hasChild = SysPermission::where('parent_id', $id)->find();
        if ($hasChild) {
            throw new BusinessException("存在子级权限无法删除");
        }
        $menu = SysPermission::where('permission_id', $id)->find();
        if (!$menu) {
            throw new BusinessException("权限不存在");
        }

        Db::startTrans();
        try {
            $menu->delete();
            // 关联删除
            SysRolePerm::where('permission_id', $id)->delete();
            Db::commit();
        } catch (\Exception $e) {
            Db::rollback();
            throw new BusinessException($e->getMessage());
        }
    }
}